﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using iTextSharp;
using iTextSharp.text;
using iTextSharp.text.pdf;
using iTextSharp.text.xml;
using System.IO;
using System.Diagnostics;
using System.Data;
using System.Data.SqlServerCe;

namespace RefOffDesktop
{
    /*
     * Class: ReportGenerator
     * 
     * Use: Class used to fill in misconduct report
     *      forms for a Match. Uses functions from the
     *      iTextSharp DLL. This library was not modified, and is
     *      freely available at:
     *      
     *      http://sourceforge.net/projects/itextsharp/
     *      
     * Author: Mike Skaife, mcs3@aber.ac.uk
     */ 
    class ReportGenerator
    {
        //The Match the reports are being generated for
        private Match thisMatch;

        //Lists of fields relating to the Multi-Caution report
        private List<String> surnameFields;
        private List<String> firstnameFields;
        private List<String> clubFields;
        private List<String> ccodeFields;
        private List<String> facodeFields;
        private List<Caution> multiCautions;
        private List<Caution> spareCautions;
        private List<SendOff> sendoffs;

        //Referee info
        private String refForename;
        private String refSurname;
        private String refName;
        private String refAddress;
        private String refNPD;
        private String refFAMOA;

        //Details required to connect to the database
        SqlCeConnection conn;
        String conString;

        public ReportGenerator(Match theMatch)
        {
            thisMatch = theMatch;
            surnameFields = new List<String>();
            firstnameFields = new List<String>();
            clubFields = new List<String>();
            ccodeFields = new List<String>();
            facodeFields = new List<String>();
            multiCautions = new List<Caution>();
            spareCautions = new List<Caution>();
            sendoffs = new List<SendOff>();

            //Add the fields from the Multi-Caution form
            //to the relevant array
            createFormArrays();
        }

        //Method called by 'Generate Reports' button on
        //the Match Details screen, to create all the
        //required reports for the Match
        public void fillForms()
        {
            //Get referee details from database
            getRefereeDetails();

            //Work out which cautions go on which form
            getMultiCautions();

            //Get hold of sending offs and their associated
            //cautions where relevant
            getSendOffs();

            //Complete all Multi-Caution reports
            fillMCForms();

            //Complete all Standard reports
            fillCMForms();
        }

        //Method used to get details of referee from database, as
        //defined in the RefereeProfile form by the user
        public void getRefereeDetails()
        {
            //Connect to the database
            connectToDatabase();

            //Pull out referee data and stick it in a dataset
            string command = @"SELECT * FROM referee";
            SqlCeDataAdapter da = new SqlCeDataAdapter(command, conn);
            DataSet ds = new DataSet();
            da.Fill(ds, "referee_details");
            DataTable dt = ds.Tables["referee_details"];
                        
            //Go through each column in DataSet record and set
            //variables in this class for use in report creation
            refForename = (string)ds.Tables[0].Rows[0]["forename"];
            refSurname = (string)ds.Tables[0].Rows[0]["surname"];
            refAddress = (string)ds.Tables[0].Rows[0]["address"];
            refNPD = (string)ds.Tables[0].Rows[0]["NPD_number"];
            refFAMOA = (string)ds.Tables[0].Rows[0]["FAMOA_number"];

            //Join the referee's firstname and surname as the
            //whole name is displayed as one field in the reports
            refName = refForename + " " + refSurname;

            //Disconnect from the database
            closeDatabaseConnection();
        }
        
        //Method used to work out which cautions to show on the
        //Multi-Caution report form - if there are two cautions for the same
        //player then they are displayed on a Standard report along
        //with details of the associated Sending Off
        public void getMultiCautions()
        {
            //Get hold of the number of Cautions in the match
            int cautions = thisMatch.matchCautions.Count;
                        
            //Go through all the Cautions in the match
            for (int i = 0; i < cautions; i++)
            {
                //Assign the current Caution to a temporary variable,
                //and indicate that another Caution with the same Player ID
                //has yet been found
                Caution temp = thisMatch.matchCautions[i];
                String found = "false";
                int k = -1;
                
                //Loop through all the cautions in the match again
                for (int j = 0; j < cautions;j++)
                {
                    //Make sure the Caution is not being compared to itself
                    if (j != i)
                    {
                        //If the current Caution in the list was given to the same
                        //player as the 'temp' Caution...
                        if(thisMatch.matchCautions[j].player_id == temp.player_id)
                        {
                            //...Indicate that a duplicate has been found
                            found = "true";
                            k = j;
                        }
                    }
                }

                //If a duplicate Caution was not found...
                if (found.Equals("false"))
                {
                    //...This caution goes on the Multi-Caution form
                    multiCautions.Add(thisMatch.matchCautions[i]);
                }
                //If a duplicate was found...
                else
                {
                    bool thereAlready = false;
                 
                    //Go through the list of Cautions ready to be displayed
                    //on the Standard report
                    for (int l = 0; l < spareCautions.Count; l++)
                    {
                        //Make sure this caution has not already been added
                        if (spareCautions[l].player_id == temp.player_id)
                        {
                            thereAlready = true;
                        }                        
                    }
                    //If the Caution has not yet been added
                    if (thereAlready == false)
                    {
                        //Add this Caution and the 'temp' Caution to the
                        //List of Cautions that will be displayed on separate
                        //Standard misconduct reports
                        spareCautions.Add(thisMatch.matchCautions[i]);
                        spareCautions.Add(thisMatch.matchCautions[k]);
                    }
                }
            }
        }

        //Method used to get hold of all the Sending Offs in the Match
        public void getSendOffs()
        {
            //Find out how many Sending Offs happened in the Match
            int sendoffsCount = thisMatch.matchSendOffs.Count;

            //Loop through all the Sending Offs
            for (int i = 0; i < sendoffsCount; i++)
            {
                //Add each one to the list of Sending Offs in this class
                sendoffs.Add(thisMatch.matchSendOffs[i]);
            }
        }

        //Method used to complete a
        //Multi-Caution Misconduct Report Form
        public void fillMCForms()
        {
            //Check that there are acutally some Cautions to be
            //displayed on this report form
            if (multiCautions.Count > 0)
            {
                //Locate the template for the report, i.e. the
                //edited misconduct report form with all required
                //fields added to it
                string pdfTemplate = @"FA\MultiCautionForm.pdf";

                //Obtain required details from the Match object:

                //Name and squad of home club
                String homeClub = thisMatch.homeTeam;
                String homeTeam = thisMatch.homeSquad;

                //Name and squad of away club
                String awayClub = thisMatch.awayTeam;
                String awayTeam = thisMatch.awaySquad;

                //Competition the Match was played in
                String competition = thisMatch.competition;

                //Football Association the report is to be sent to
                String association = thisMatch.association;

                //Date the Match was played on
                String matchDate = thisMatch.db_date.ToString("dd/MMM/yyyy");

                //Date that Match was played on for use in new filename
                String matchFileDate = thisMatch.db_date.ToString("dd-MMM-yyyy");

                //Create the name of the new file that will be created, i.e. the
                //completed report. This includes name of home and away team, and
                //the date the Match was played on
                String nameFile = homeClub + "-v-" + awayClub + matchFileDate + "MC.pdf";

                //Define the location and name of the report being created
                string newFile = @"CompletedReports\" + nameFile;

                //Open new iTextSharp PdfReader object and pass it the filename
                //of the report template, so fields can be accessed
                PdfReader pdfReader = new PdfReader(pdfTemplate);

                //Open new iTextSharp PdfStamper object enabling forms to be written
                //to and a new file to be created
                PdfStamper pdfStamper = new PdfStamper(pdfReader, new FileStream(
                    newFile, FileMode.Create));

                //Get hold of all fields in report using iTextSharp
                //AcroFields object
                AcroFields pdfFormFields = pdfStamper.AcroFields;

                //Set values of all report form fields:
                
                //referee details
                pdfFormFields.SetField("referee_name", refName);
                pdfFormFields.SetField("referee_address", refAddress);
                pdfFormFields.SetField("npd", refNPD);
                pdfFormFields.SetField("famoa", refFAMOA);

                //Todays date, i.e. when the report was completed
                pdfFormFields.SetField("form_date", DateTime.Now.ToString("dd/MMM/yyyy"));

                //Match details
                pdfFormFields.SetField("football_association", association);
                pdfFormFields.SetField("home_club", homeClub);
                pdfFormFields.SetField("home_squad", homeTeam);
                pdfFormFields.SetField("away_club", awayClub);
                pdfFormFields.SetField("away_squad", awayTeam);
                pdfFormFields.SetField("competition", competition);
                pdfFormFields.SetField("match_date", matchDate);

                //Cautions
                int cautions = multiCautions.Count;

                //Loop through each of the Cautions in the Multi-Caution List
                for (int i = 0; i < cautions; i++)
                {
                    //Caution details for each Caution in the List
                    pdfFormFields.SetField(surnameFields[i], multiCautions[i].player_surname);
                    pdfFormFields.SetField(firstnameFields[i], multiCautions[i].player_firstname);
                    pdfFormFields.SetField(clubFields[i], multiCautions[i].club);
                    pdfFormFields.SetField(ccodeFields[i], multiCautions[i].caution_code);
                    //If this Caution has a code of 'C1'...
                    if (!(multiCautions[i].c1_code.Equals(null)))
                    {
                        //...Also fill in the corresponding C1 field
                        pdfFormFields.SetField(facodeFields[i], multiCautions[i].c1_code);
                    }
                    //Otherwise mark the C1 field as 'blank'
                    else
                    {
                        pdfFormFields.SetField(facodeFields[i], "-");
                    }
                }

                //Flatten the completed misconduct report form to remove
                //editting options, preventing subsequent manual edits
                pdfStamper.FormFlattening = true;

                //Close the PDF form, saving the completed report
                //in the location specified earlier
                pdfStamper.Close();

                //Display the filename and creation date of this report
                //on the 'Reports' tab of the Match Details screen
                ListViewItem report = new ListViewItem(nameFile);
                report.SubItems.Add(DateTime.Now.ToString("dd/MMM/yyyy"));
                thisMatch.matchReportsLst.Items.Add(report);
                thisMatch.matchReports.Add(nameFile);
            }
        }

        //Method used to complete all required
        //Standard Misconduct Report Forms
        public void fillCMForms()
        {
            //Check that there are actually some Sending Offs in this Match
            if (sendoffs.Count > 0)
            {
                //Locate the template for the report, i.e. the
                //edited misconduct report form with all required
                //fields added to it
                string pdfTemplate = @"FA\MisconductReportForm.pdf";

                //Obtain required details from the Match object:

                //Name and squad of home club
                String homeClub = thisMatch.homeTeam;
                String homeTeam = thisMatch.homeSquad;

                //Name and squad of away club
                String awayClub = thisMatch.awayTeam;
                String awayTeam = thisMatch.awaySquad;

                //Competition the Match is being played in
                String competition = thisMatch.competition;

                //Football Association this report is being sent to
                String footballAssociation = thisMatch.association;

                //Date the Match took place
                String matchDate = thisMatch.db_date.ToString("dd/MMM/yyyy");

                //Date the Match took place, for use in filename of new report
                String matchFileDate = thisMatch.db_date.ToString("dd-MMM-yyyy");

                //Obtain the number of Sending Offs in the Match
                int numOfReports = sendoffs.Count;

                //Create a new report for each separate Sending Off
                for (int reportCounter = 0; reportCounter < numOfReports; reportCounter++)
                {
                    //Define the name of the new report file, consisting of the
                    //name of the two clubs, the date the Match was played and
                    //what number report this is
                    String nameFile = homeClub + "-v-" + awayClub + matchFileDate + "CM" + (reportCounter + 1) + ".pdf";

                    //Indicate name and location of completed report file
                    string newFile = @"CompletedReports\" + nameFile;

                    //Open new iTextSharp PdfReader object and pass it the filename
                    //of the report template, so fields can be accessed
                    PdfReader pdfReader = new PdfReader(pdfTemplate);

                    //Open new iTextSharp PdfStamper object enabling forms to be written
                    //to and a new file to be created
                    PdfStamper pdfStamper = new PdfStamper(pdfReader, new FileStream(
                        newFile, FileMode.Create));

                    //Get hold of all fields in report using iTextSharp
                    //AcroFields object
                    AcroFields pdfFormFields = pdfStamper.AcroFields;

                    //Set values of all report form fields:

                    //Referee details
                    pdfFormFields.SetField("referee_name", refName);
                    pdfFormFields.SetField("referee_address", refAddress);
                    pdfFormFields.SetField("npd", refNPD);
                    pdfFormFields.SetField("famoa", refFAMOA);

                    //Date of report creation, i.e. today
                    pdfFormFields.SetField("form_date", DateTime.Now.ToString("dd/MM/yyyy"));

                    //Match details
                    pdfFormFields.SetField("football_association", footballAssociation);
                    pdfFormFields.SetField("home_club", homeClub);
                    pdfFormFields.SetField("home_squad", homeTeam);
                    pdfFormFields.SetField("away_club", awayClub);
                    pdfFormFields.SetField("away_squad", awayTeam);
                    pdfFormFields.SetField("competition", competition);
                    pdfFormFields.SetField("match_date", matchDate);

                    //Player details
                    pdfFormFields.SetField("player_name", sendoffs[reportCounter].player_name);
                    pdfFormFields.SetField("player_club", sendoffs[reportCounter].club);

                    //The three parts of the Incident Details field of the
                    //form - Sending Off, Caution 1 and Caution 2, as required
                    //for each Sending Off incident
                    String incidentDetails1 = "";
                    String incidentDetails2 = "";
                    String incidentDetails3 = "";

                    //Get the database id of the Player who was sent off
                    int thisPlayerid = sendoffs[reportCounter].player_id;

                    //The number of cautions in the List of cautions that resulted
                    //in a Sending Off, i.e. two for each player
                    int numOfCautions = spareCautions.Count;

                    //If the current Sending Off has a code of 'S7', then the player
                    //was sent off for two separate Cautions
                    if (sendoffs[reportCounter].sendoff_code.Equals("S7"))
                    {
                        //The current field to be written to - fields 2 and 3 within
                        //the 'Incident Details' section are used to hold details of
                        //the two Cautions
                        int currentField = 2;

                        //Go through the List of Cautions for the Match
                        for (int j = 0; j < numOfCautions; j++)
                        {
                            //When a Caution for this player is found
                            if (spareCautions[j].player_id == thisPlayerid)
                            {
                                //Find out if the caution has a code of 'C1'
                                if (spareCautions[j].caution_code.Equals("C1"))
                                {
                                    if (currentField == 2)
                                    {
                                        //Write details of this Caution to the relevant part
                                        //of the Incident Details section of the form
                                        incidentDetails2 = "Caution: " + spareCautions[j].caution_code + ", " + spareCautions[j].c1_code + "\r\n";
                                    }
                                    else
                                    {
                                        //Write details of this Caution to the relevant part
                                        //of the Incident Details section of the form
                                        incidentDetails3 = "Caution: " + spareCautions[j].caution_code + ", " + spareCautions[j].c1_code + "\r\n";
                                    }
                                }
                                //This code runs if the Caution does not have a code of 'C1'
                                else
                                {
                                    if (currentField == 2)
                                    {
                                        //Write details of this Caution to the relevant part
                                        //of the Incident Details section of the form
                                        incidentDetails2 = "Caution: " + spareCautions[j].caution_code + "\r\n";
                                    }
                                    else
                                    {
                                        //Write details of this Caution to the relevant part
                                        //of the Incident Details section of the form
                                        incidentDetails3 = "Caution: " + spareCautions[j].caution_code + "\r\n";
                                    }
                                }
                                //Indicate which field is to be written to next
                                currentField++;
                            }
                        }
                    }
                    //Fill in details of the Sending Off in the Incident Details
                    //section of the report form
                    incidentDetails1 = "Sending Off: " + sendoffs[reportCounter].sendoff_code;

                    //Complete the Incident Details section of the form
                    pdfFormFields.SetField("incident_details1", incidentDetails1);
                    pdfFormFields.SetField("incident_details2", incidentDetails2);
                    pdfFormFields.SetField("incident_details3", incidentDetails3);
                    pdfFormFields.SetField("s_code", sendoffs[reportCounter].sendoff_code);

                    //Flatten the completed misconduct report form to remove
                    //editting options, preventing subsequent manual edits
                    pdfStamper.FormFlattening = false;

                    //Close the PDF form, saving the completed report
                    //in the location specified earlier
                    pdfStamper.Close();

                    //Display the filename and creation date of this report
                    //on the 'Reports' tab of the Match Details screen
                    ListViewItem report = new ListViewItem(nameFile);
                    report.SubItems.Add(DateTime.Now.ToString("dd/MMM/yyyy"));
                    thisMatch.matchReportsLst.Items.Add(report);
                    thisMatch.matchReports.Add(nameFile);
                }
            }
        }

        //Method used during creation of Multi-Caution report, which
        //gets hold of all fields in the Caution section of the form,
        //so that each line of the table can be written to as necessary
        //during creation of the report
        void createFormArrays()
        {
            //Loop through all 11 lines of the Caution table on the form,
            //and add each field to the corresponding field array for
            //later reference
            for (int i = 1; i < 11; i++)
            {
                //Surname
                surnameFields.Add(i + "_surname");
                
                //Firstname
                firstnameFields.Add(i + "_firstname");
                
                //Club
                clubFields.Add(i + "_club");
                
                //Disciplinary Code
                ccodeFields.Add(i + "_ccode");
                
                //C1 Code
                facodeFields.Add(i + "_facode");
            }
        }

        //Method to connect to the database
        private void connectToDatabase()
        {
            // Retrieve the connection string
            conString = @"Data Source=RefOff_DB.sdf";
            
            // Open the connection using the connection string
            conn = new SqlCeConnection(conString);
            conn.Open();
        }

        //Method to disconnect from database
        private void closeDatabaseConnection()
        {
            //Close the database connection
            conn.Close();
        }
    }
}
